//go:build js || wasm

package godom

import "syscall/js"

type CDATASectionWrapper interface {
	NodeWrapper
}

type CDATASection struct {
	Node
}

type CommentWrapper interface {
	NodeWrapper
}

type Comment struct {
	Node
}

// XPathExpressionWrapper
// https://developer.mozilla.org/en-US/docs/Web/API/XPathExpression
type XPathExpressionWrapper interface {
	JSWrapper

	Evaluate(contextNode NodeWrapper) XPathResultWrapper
}

type XPathExpression struct {
	JsValue js.Value
}

func (x *XPathExpression) Evaluate(contextNode NodeWrapper) XPathResultWrapper {
	return &XPathResult{
		JsValue: x.JsValue.Call("evaluate", contextNode.JSValue()),
	}
}
func (x *XPathExpression) JSValue() js.Value {
	return x.JsValue
}

// XPathResultWrapper
// https://developer.mozilla.org/en-US/docs/Web/API/XPathResult
type XPathResultWrapper interface {
	JSWrapper

	BooleanValue() bool
	InvalidIteratorState() bool
	NumberValue() float64
	ResultType() string
	SingleNodeValue() NodeWrapper
	SnapshotLength() int
	StringValue() string

	IterateNext() NodeWrapper
	SnapshotItem(i float64) NodeWrapper
}

type XPathResult struct {
	JsValue js.Value
}

func (x *XPathResult) BooleanValue() bool {
	return x.JsValue.Get("boolean").Bool()
}

func (x *XPathResult) InvalidIteratorState() bool {
	return x.JsValue.Get("invalidIteratorState").Bool()
}

func (x *XPathResult) NumberValue() float64 {
	return x.JsValue.Get("numberValue").Float()
}

func (x *XPathResult) ResultType() string {
	return x.JsValue.Get("resultType").String()
}

func (x *XPathResult) SingleNodeValue() NodeWrapper {
	return &Node{
		x.JsValue.Get("singleNodeValue"),
	}
}

func (x *XPathResult) SnapshotLength() int {
	return x.JsValue.Get("snapshotLength").Int()
}

func (x *XPathResult) StringValue() string {
	return x.JsValue.Get("stringValue").String()
}

func (x *XPathResult) IterateNext() NodeWrapper {
	return &Node{
		x.JsValue.Call("iterateNext"),
	}
}

func (x *XPathResult) SnapshotItem(i float64) NodeWrapper {
	return &Node{
		x.JsValue.Call("snapshotItem", i),
	}
}

func (x *XPathResult) JSValue() js.Value {
	return x.JsValue
}

// RangeWrapper
// todo: добавить свойства
// https://developer.mozilla.org/en-US/docs/Web/API/Range
type RangeWrapper interface {
	JSWrapper
}

type Range struct {
	jsValue js.Value
}

func (x *Range) JSValue() js.Value {
	return x.jsValue
}

// TreeWalkerWrapper
// https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
type TreeWalkerWrapper interface {
	JSWrapper

	CurrentNode() NodeWrapper
	Filter() NodeWrapper
	Root() NodeWrapper
	WhatToShow() string

	FirstChild() NodeWrapper
	LastChild() NodeWrapper
	NextNode() NodeWrapper
	NextSibling() NodeWrapper
	ParentNode() NodeWrapper
	PreviousNode() NodeWrapper
	PreviousSibling() NodeWrapper
}

type TreeWalker struct {
	jsValue js.Value
}

func (t *TreeWalker) JSValue() js.Value {
	return t.jsValue
}

func (t *TreeWalker) CurrentNode() NodeWrapper {
	return &Node{
		t.jsValue.Get("currentNode"),
	}
}

func (t *TreeWalker) Filter() NodeWrapper {
	return &Node{t.jsValue.Get("filter")}
}

func (t *TreeWalker) Root() NodeWrapper {
	return &Node{t.jsValue.Get("root")}
}

func (t *TreeWalker) WhatToShow() string {
	return t.jsValue.Get("whatToShow").String()
}

func (t *TreeWalker) FirstChild() NodeWrapper {
	return &Node{t.jsValue.Call("firstChild")}
}

func (t *TreeWalker) LastChild() NodeWrapper {
	return &Node{t.jsValue.Call("lastChild")}
}

func (t *TreeWalker) NextNode() NodeWrapper {
	return &Node{t.jsValue.Call("nextNode")}
}

func (t *TreeWalker) NextSibling() NodeWrapper {
	return &Node{t.jsValue.Call("nextSibling")}
}

func (t *TreeWalker) ParentNode() NodeWrapper {
	return &Node{t.jsValue.Call("parentNode")}
}

func (t *TreeWalker) PreviousNode() NodeWrapper {
	return &Node{t.jsValue.Call("previousNode")}
}

func (t *TreeWalker) PreviousSibling() NodeWrapper {
	return &Node{t.jsValue.Call("previousSibling")}
}

// SelectorWrapper
// https://developer.mozilla.org/en-US/docs/Web/API/Selection
type SelectorWrapper interface {
	JSWrapper

	AnchorNode() NodeWrapper
	AnchorOffset() int
	Direction() string
	FocusNode() NodeWrapper
	FocusOffset() int
	IsCollapsed() bool
	RangeCount() int
	Type() string

	AddRange(r RangeWrapper)
	Collapse(node NodeWrapper)
	CollapseToEnd()
	CollapseToStart()
	ContainsNode(n NodeWrapper) bool
	DeleteFromDocument()
	Empty()
	Extend(node NodeWrapper, offset int)
	GetRangeAt(i int) RangeWrapper
	Modify(alter, direction, granularity string)
	RemoveAllRanges()
	RemoveRange(r RangeWrapper)
	SelectAllChildren(parentNode NodeWrapper)
	SetBaseAndExtent(anchorNode NodeWrapper, anchorOffset int, focusNode NodeWrapper, focusOffset int)
	SetPosition(node NodeWrapper, offset int)
	ToString() string
}

type Selector struct {
	jsValue js.Value
}

func (s *Selector) JSValue() js.Value {
	return s.jsValue
}

func (s *Selector) AnchorNode() NodeWrapper {
	return &Node{s.jsValue.Get("anchorNode")}
}

func (s *Selector) AnchorOffset() int {
	return s.jsValue.Get("anchorOffset").Int()
}

func (s *Selector) Direction() string {
	return s.jsValue.Get("direction").String()
}

func (s *Selector) FocusNode() NodeWrapper {
	return &Node{s.jsValue.Get("focusNode")}
}

func (s *Selector) FocusOffset() int {
	return s.jsValue.Get("focusOffset").Int()
}

func (s *Selector) IsCollapsed() bool {
	return s.jsValue.Get("isCollapsed").Bool()
}

func (s *Selector) RangeCount() int {
	return s.jsValue.Get("rangeCount").Int()
}

func (s *Selector) Type() string {
	return s.jsValue.Get("type").String()
}

func (s *Selector) AddRange(r RangeWrapper) {
	s.jsValue.Call("addRange", r.JSValue())
}

func (s *Selector) Collapse(node NodeWrapper) {
	s.jsValue.Call("collapse", node.JSValue())
}

func (s *Selector) CollapseToEnd() {
	s.jsValue.Call("collapseToEnd")
}

func (s *Selector) CollapseToStart() {
	s.jsValue.Call("collapseToStart")
}

func (s *Selector) ContainsNode(n NodeWrapper) bool {
	return s.jsValue.Call("containsNode", n.JSValue()).Bool()
}

func (s *Selector) DeleteFromDocument() {
	s.jsValue.Call("deleteFromDocument")
}

func (s *Selector) Empty() {
	s.jsValue.Call("empty")
}

func (s *Selector) Extend(node NodeWrapper, offset int) {
	s.jsValue.Call("extend", node.JSValue(), offset)
}

func (s *Selector) GetRangeAt(i int) RangeWrapper {
	return &Range{s.jsValue.Call("getRangeAt", i)}
}

func (s *Selector) Modify(alter, direction, granularity string) {
	s.jsValue.Call("modify", alter, direction, granularity)
}

func (s *Selector) RemoveAllRanges() {
	s.jsValue.Call("removeAllRanges")
}

func (s *Selector) RemoveRange(r RangeWrapper) {
	s.jsValue.Call("removeRange", r.JSValue())
}

func (s *Selector) SelectAllChildren(parentNode NodeWrapper) {
	s.jsValue.Call("selectAllChildren", parentNode.JSValue())
}

func (s *Selector) SetBaseAndExtent(anchorNode NodeWrapper, anchorOffset int, focusNode NodeWrapper, focusOffset int) {
	s.jsValue.Call("setBaseAndExtent", anchorNode.JSValue(), anchorOffset, focusNode.JSValue(), focusOffset)
}

func (s *Selector) SetPosition(node NodeWrapper, offset int) {
	s.jsValue.Call("setPosition", node.JSValue(), offset)
}

func (s *Selector) ToString() string {
	return s.jsValue.Get("toString").String()
}
